# Context switch
#
#   void swtch(struct context **old, struct context *new);
# 
# Save the current registers on the stack, creating
# a struct context, and save its address in *old.
# Switch stacks to new and pop previously-saved registers.

.globl swtch
swtch:
  # [esp]: return address. ret to proc.c:347 "switchkvm();"
  # [esp+4]->pp_scheduler_context to store cpu state of kernel scheduler thread.
  movl 4(%esp), %eax # eax=pp_scheduler_context
  # [esp+8]->p_new_context, from which loading cpu state of new process.
  movl 8(%esp), %edx # edx=p_new_context

  # Save old callee-saved registers
  # construct (filling) struct context on current kernel stack.
             # +0x10: context.eip = (%esp) = ret_addr
  pushl %ebp # +0x0c: context.ebp
  pushl %ebx # +0x08: context.ebx
  pushl %esi # +0x04: context.esi
  pushl %edi # +0x00: context.edi
             

  # Switch stacks
  # *pp_scheduler_context = esp;
  movl %esp, (%eax) # eax = pp_scheduler_context
  # esp = p_new_context
  movl %edx, %esp   # edx = p_new_context

  # Load new callee-saved registers
  popl %edi
  popl %esi
  popl %ebx
  popl %ebp
  ret
